package com.xgk.boot.module.core.service.payment;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.xgk.boot.framework.common.constant.ErrorCodeConstants;
import com.xgk.boot.framework.common.exception.util.ServiceExceptionUtil;
import com.xgk.boot.framework.common.util.object.BeanUtils;
import com.xgk.boot.framework.redis.core.RedisLockManager;
import com.xgk.boot.framework.security.core.util.SecurityFrameworkUtils;
import com.xgk.boot.module.core.controller.admin.channel.vo.spapi.ApiSaveReqVO;
import com.xgk.boot.module.core.controller.admin.payment.vo.payment.PaymentApproveVO;
import com.xgk.boot.module.core.controller.admin.payment.vo.payment.PaymentPageReqVO;
import com.xgk.boot.module.core.controller.admin.payment.vo.payment.PaymentPageRespVO;
import com.xgk.boot.module.core.controller.admin.payment.vo.payment.PaymentSaveReqVO;
import com.xgk.boot.module.core.dal.dto.PaymentSummaryDto;
import com.xgk.boot.module.core.dal.entity.channel.ApiServiceDO;
import com.xgk.boot.module.core.dal.entity.customer.CustomerDO;
import com.xgk.boot.module.core.dal.entity.payment.PaymentRecordsDO;
import com.xgk.boot.module.core.dal.iservice.PaymentRecordsService;
import com.xgk.boot.module.core.dal.mapper.customer.CustomerMapper;
import com.xgk.boot.module.core.dal.mapper.payment.PaymentRecordsMapper;
import com.xgk.boot.module.core.dal.redis.RedisLockConstants;
import com.xgk.boot.module.core.enums.biz.ApprovalTypeEnum;
import com.xgk.boot.module.core.service.customer.CustomerBalanceServiceImpl;
import com.xgk.boot.module.core.service.customer.CustomerServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import static com.xgk.boot.module.core.enums.LogRecordConstants.*;


/**
 * 支付管理，
 * 包含 cm-客户、su-供应商、sp-服务商 的收支付信息
 */
@Slf4j
@Service
public class PaymentRecordsServiceImpl extends ServiceImpl<PaymentRecordsMapper, PaymentRecordsDO> implements PaymentRecordsService {

    @Resource
    private PaymentRecordsMapper paymentRecordsMapper;
    @Resource
    private CustomerServiceImpl customerService;
    @Resource
    private CustomerBalanceServiceImpl customerBalanceServiceImpl;
    private static final int MAX_RETRY = 10;

    @Resource
    private RedisLockManager lockManager;

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
    private static final AtomicInteger sequence = new AtomicInteger(0);
    private static final int MAX_SEQUENCE = 9999;
    public List<PaymentSummaryDto>  listCustomerTotalPay(Collection<String> custCodes){
        if(CollUtil.isEmpty(custCodes)){
            return Lists.newArrayList();
        }
//        List<PaymentSummaryDto> paymentSummaryDtos = this.baseMapper.summaryPayAmout(custCodes, SoEnum.Customer.getType(), PayTypeEnum.Receive_Payment.getType());
//        return paymentSummaryDtos;
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_PAYMENT_TYPE, subType = SYSTEM_PAYMENT_CREATE_TYPE, bizNo = "{{#py.id}}",
            success = SYSTEM_PAYMENT_CREATE_SUCCESS)
    public Long createPayment(PaymentSaveReqVO createReqVO) {
        PaymentRecordsDO prd = new PaymentRecordsDO();
        prd.setAmount(BigDecimal.valueOf(createReqVO.getAmount()));
        prd.setRealAmount(BigDecimal.valueOf(createReqVO.getRealAmount()));

        Long customerId = Long.valueOf(createReqVO.getCustomerId());
        prd.setCustomerId(customerId);
        CustomerDO customerDO = customerService.getById(customerId);
        prd.setCustomerCode(customerDO.getCustomerCode());

        prd.setPmCode(createReqVO.getPmCode());
        prd.setPayerAccount(createReqVO.getPayerAccount());
        prd.setPayerAccountName(createReqVO.getPayerAccountName());
        prd.setPayBank(createReqVO.getPayBank());
        prd.setCurrencyCode(createReqVO.getCurrencyCode());
        prd.setUpperAmount(createReqVO.getAmountUpper());
//        TODO
//        prd.setCurrencyRate();
        prd.setNote(createReqVO.getNote());
        prd.setAttachment(createReqVO.getAttachment());
        prd.setTransactionNo(generateTransactionNo());
        paymentRecordsMapper.insert(prd);
        LogRecordContext.putVariable("py", prd);
        return prd.getId();
    }

    @Override
    @LogRecord(type = SYSTEM_PAYMENT_TYPE, subType = SYSTEM_PAYMENT_UPDATE_TYPE, bizNo = "{{#py.id}}",
            success = SYSTEM_PAYMENT_UPDATE_SUCCESS)
    public void updatePayment(PaymentSaveReqVO updateReqVO) {
        String id = updateReqVO.getId();
        PaymentRecordsDO prd = paymentRecordsMapper.selectById(id);
        if(prd == null){
            throw new RuntimeException("支付记录不存在");
        }
        prd.setAmount(BigDecimal.valueOf(updateReqVO.getAmount()));
        prd.setRealAmount(BigDecimal.valueOf(updateReqVO.getRealAmount()));
        prd.setPmCode(updateReqVO.getPmCode());
        prd.setPayerAccount(updateReqVO.getPayerAccount());
        prd.setPayerAccountName(updateReqVO.getPayerAccountName());
        prd.setPayBank(updateReqVO.getPayBank());
        prd.setCurrencyCode(updateReqVO.getCurrencyCode());
        prd.setUpperAmount(updateReqVO.getAmountUpper());
        prd.setNote(updateReqVO.getNote());
        prd.setAttachment(updateReqVO.getAttachment());
        prd.setTransactionNo(generateTransactionNo());
        paymentRecordsMapper.updateById(prd);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("py", prd);
    }

    public String generateTransactionNo() {
        int retryCount = 0;

        while (retryCount < MAX_RETRY) {
            String no = tryNumber();

            // 检查数据库中是否已存在该流水号
            Long count = paymentRecordsMapper.selectCount(PaymentRecordsDO::getTransactionNo, no);
            if (count == null || count == 0) {
                return no; // 返回唯一的流水号
            }

            retryCount++;
        }

        throw new RuntimeException("无法生成唯一的交易流水号，已达到最大重试次数: " + MAX_RETRY);
    }
    

    private String tryNumber() {
        String date = DATE_FORMAT.format(new Date());
        String uuidPart = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        return date + uuidPart;
    }

    @Override
    public Page<PaymentPageRespVO> getPaymentPage(PaymentPageReqVO reqVO) {

//        PageResult<PaymentRecordsDO> pageList = paymentRecordsMapper.selectPage(pageReqVO, new LambdaQueryWrapperX<PaymentRecordsDO>()
//                .eqIfPresent(PaymentRecordsDO::getPmCode, pageReqVO.getPmCode())
//                .betweenIfPresent(BaseDO::getCreateTime, new LocalDate[]{pageReqVO.getStartTime(), pageReqVO.getEndTime()})
//                .orderByAsc(PaymentRecordsDO::getId));
//
//        if (pageList.getTotal()==0) {
//            return new PageResult<>(new ArrayList(), 0L);
//        }
//        List<PaymentRecordsDO> records = pageList.getData();
//        Set<Long> customerIds = records.stream()
//                .map(PaymentRecordsDO::getCustomerId)
//                .collect(Collectors.toSet());
//        Map<Long, CustomerDO> customerMap = customerMapper.selectBatchIds(customerIds)
//                .stream()
//                .collect(Collectors.toMap(CustomerDO::getId, Function.identity()));
//        List<PaymentRecordsDTO> collect = records.stream().map(record -> {
//            PaymentRecordsDTO dto = new PaymentRecordsDTO();
//            // 复制基本属性
//            BeanUtils.copyProperties(record, dto);
//
//            // 设置客户信息
//            CustomerDO customer = customerMap.get(record.getCustomerId());
//            if(customer != null) {
//                dto.setCustomerName(customer.getCustomerName());
//                dto.setCustomerCode(customer.getCustomerCode());
//            }
//
//            return dto;
//        }).collect(Collectors.toList());
//        PageResult<PaymentRecordsDTO> pageResult = new PageResult<>(collect, pageList.getTotal());
//        return pageResult;
        
        Page<PaymentPageRespVO> page = new Page<>(reqVO.getCurrent(), reqVO.getPageSize());

        // 执行分页查询
        return paymentRecordsMapper.selectPaymentPage(page, reqVO);
    }

    @Transactional
    @Override
    @LogRecord(type = SYSTEM_PAYMENT_TYPE, subType = SYSTEM_PAYMENT_APPROVE_TYPE, bizNo = "{{#py.id}}",
            success = SYSTEM_PAYMENT_APPROVE_SUCCESS)
    public Long approvePayment(PaymentApproveVO approveVO) {
        PaymentRecordsDO paymentRecordsDO = paymentRecordsMapper.selectById(approveVO.getId());
        boolean locked = false;
        String lockName = RedisLockConstants.PAYMENT_APPROVAL + approveVO.getId();
        try {
            locked = lockManager.tryLock(lockName,10, 50);
            if(!locked){
                log.error("获取充值审批锁失败,{}", lockName);
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.REQUEST_EXCEPTION, "get order sync lock failed,"+lockName);
            }
            if(paymentRecordsDO!=null){
                if(!paymentRecordsDO.getStatus().equals(ApprovalTypeEnum.WAIT_APPROVAL.getValue())) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.REQUEST_EXCEPTION, "充值记录不允许审批操作");
                }

                paymentRecordsDO.setStatus(approveVO.getStatus());
                paymentRecordsDO.setOperatorDesc(approveVO.getOperatorDesc());
                paymentRecordsDO.setConfirmTime(new Date());
                paymentRecordsDO.setConfirmId(SecurityFrameworkUtils.getLoginUserId());
                paymentRecordsMapper.updateById(paymentRecordsDO);
                if(approveVO.getStatus() == ApprovalTypeEnum.PASS.getValue()) {
                    // 审核通过，更新客户余额
                    CustomerDO customerDO = customerService.getById(paymentRecordsDO.getCustomerId());
                    customerBalanceServiceImpl.customerBalanceRecharge(customerDO.getCustomerCode(),paymentRecordsDO.getRealAmount());
                }
                LogRecordContext.putVariable("py", paymentRecordsDO);
                return paymentRecordsDO.getId();
            }
        } catch (InterruptedException e) {
            log.error("向充值记录{}, 执行审批操作失败：{}", approveVO.getId(), e.getMessage());
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.REQUEST_EXCEPTION, e.getMessage());
        }finally {
            if (locked) {
                lockManager.unlock(lockName);
            }
        }
        return 0L;
    }
}
